home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 1 (Walnut Creek)
/
Aminet - June 1993 [Walnut Creek].iso
/
usenet
/
sources
/
volume91
/
utilitys
/
beav_132
/
part05
/
file.c
next >
Wrap
C/C++ Source or Header
|
1991-11-13
|
19KB
|
787 lines
/*
* File commands.
*/
#include <sys/types.h>
#include <fcntl.h>
#include <sys/stat.h>
#include "def.h"
char load_file ();
char readin ();
void makename ();
bool writeout ();
bool parse_f_name ();
A32 ffseek ();
extern char MSG_rd_file[];
extern char MSG_trash[];
extern char MSG_ins_file[];
extern char MSG_not_fnd[];
extern char MSG_visit[];
extern char MSG_view[];
extern char MSG_buf_ex[];
extern char MSG_old_buf[];
extern char MSG_buf_nam[];
extern char MSG_cnt_cr[];
extern char MSG_reading[];
extern char MSG_read_lx[];
extern char MSG_no_mem_rd[];
extern char MSG_wr_file[];
extern char MSG_no_fn[];
extern char MSG_bk_err[];
extern char MSG_writing[];
extern char MSG_wrot_n[];
extern char MSG_fil_nam[];
extern char MSG_null[];
extern char ERR_parse_fn[];
extern char ERR_addr_neg[];
extern char ERR_f_size[];
static int ughlyflag = FALSE;
/*
* Read a file into the current
* buffer. This is really easy; all you do it
* find the name of the file, and call the standard
* "read a file into the current buffer" code.
*/
char fileread ()
{
register char s;
char fname[NFILEN];
A32 start, end;
if ((s = ereply (MSG_rd_file, fname, NFILEN, NULL)) != TRUE)
return (s);
if (parse_f_name (fname, &start, &end))
{
adjustcase (fname);
return (readin (fname, start, end));
}
return (TRUE);
}
/* insert file into current buffer - use readin, and yank
*/
char fileinsert ()
{
register char s;
char bname[NBUFN],
fname[NFILEN];
A32 start, end;
register char *trash = MSG_trash;
strcpy (bname, curbp -> b_bname);/* save current buffer */
if ((s = _usebuffer (trash)) == 0)/* temp buffer */
return (s);
if ((s = ereply (MSG_ins_file, fname, NFILEN, NULL)) != TRUE)
return (s);
/* if file name and starting and ending addresses are good */
if (parse_f_name (fname, &start, &end))
{
adjustcase (fname);
if ((s = readin (fname, start, end)) == 0)
{
writ_echo (MSG_not_fnd);
_usebuffer (bname);
_killbuffer (trash);
return (s);
}
if ((s = _usebuffer (bname)) == 0)
{
_killbuffer (trash);
return (s);
}
if ((s = _yankbuffer (trash)) == 0)
{
_killbuffer (trash);
return (s);
}
writ_echo (okmsg);
}
else
{
_usebuffer (bname);
_killbuffer (trash);
return (FALSE);
}
if ((s = _killbuffer (trash)) == 0)
return (s);
wind_on_dot (curwp);
return (s);
}
/*
* Select a file for editing.
* Look around to see if you can find the
* fine in another buffer; if you can find it
* just switch to the buffer. If you cannot find
* the file, create a new buffer, read in the
* text, and switch to the new buffer.
*
* also various hacked versions for auto load, and
* file-vist with auto window split, and readonly (view-file) (jam)
*/
char file_visit (f, n, k)
{
char fname[NFILEN];
char s;
A32 start, end;
if ((s = ereply (MSG_visit, fname, NFILEN, NULL)) != TRUE)
return (s);
if (!parse_f_name (fname, &start, &end))
return (FALSE);
splitwind ();
return (load_file (fname, start, end));
}
/* like filevisit, only read only
*/
char viewfile ()
{
char fname[NFILEN];
char s;
A32 start, end;
if ((s = ereply (MSG_view, fname, NFILEN, NULL)) != TRUE)
return (s);
ughlyflag = TRUE;
if (!parse_f_name (fname, &start, &end))
return (FALSE);
s = load_file (fname, start, end);
if (s)
curbp -> b_flag |= BFVIEW;
ughlyflag = FALSE;
return (s);
}
char filevisit ()
{
char fname[NFILEN];
char s;
A32 start, end;
if ((s = ereply (MSG_visit, fname, NFILEN, NULL)) != TRUE)
return (s);
if (!parse_f_name (fname, &start, &end))
return (FALSE);
return (load_file (fname, start, end));
}
char load_file (fname, start, end) /* jam */
char *fname;
A32 start, end;
{
register BUFFER * bp;
register WINDOW * wp;
register LINE * lp;
register int i;
char s;
char bname[NBUFN];
extern int initial_load; /* jam */
static int append = 0;
adjustcase (fname);
for (bp = bheadp; bp != NULL; bp = bp -> b_bufp)
{
if (strcmp (bp -> b_fname, fname) == 0)
{
if (ughlyflag == TRUE)
{
writ_echo (MSG_buf_ex);
return (FALSE);
}
if (--curbp -> b_nwnd == 0)
{
curbp -> b_type = BTFILE;
curbp -> b_dotp = curwp -> w_dotp;
curbp -> b_doto = curwp -> w_doto;
curbp -> b_unit_offset = curwp -> w_unit_offset;
curbp -> b_markp = curwp -> w_markp;
curbp -> b_marko = curwp -> w_marko;
}
curbp = bp;
curwp -> w_bufp = bp;
if (bp -> b_nwnd++ == 0)
{
curwp -> w_dotp = bp -> b_dotp;
curwp -> w_doto = bp -> b_doto;
curwp -> w_unit_offset = bp -> b_unit_offset;
curwp -> w_markp = bp -> b_markp;
curwp -> w_marko = bp -> b_marko;
}
else
{
wp = wheadp;
while (wp != NULL)
{
if (wp != curwp && wp -> w_bufp == bp)
{
curwp -> w_dotp = wp -> w_dotp;
curwp -> w_doto = wp -> w_doto;
curwp -> w_unit_offset = wp -> w_unit_offset;
curwp -> w_markp = wp -> w_markp;
curwp -> w_marko = wp -> w_marko;
break;
}
wp = wp -> w_wndp;
}
}
lp = curwp -> w_dotp;
i = curwp -> w_ntrows / 2;
while (i-- && lback (lp) != curbp -> b_linep)
lp = lback (lp);
curwp -> w_linep = lp;
curwp -> w_flag |= WFMODE | WFHARD;
if (kbdmop == NULL)
{
writ_echo (MSG_old_buf);
}
return (TRUE);
}
}
makename (bname, fname); /* New buffer name. */
while ((bp = bfind (bname, FALSE)) != NULL)
{
if (initial_load) /* patch old name */
{
funky_name (bname, append++);
bp = NULL;
break;
}
s = ereply (MSG_buf_nam, bname, NBUFN, NULL);
if (s == ABORT) /* ^G to just quit */
return (s);
if (strcmp (bp -> b_bname, bname) == 0 || s == FALSE)
{
/* CR to clobber it */
makename (bname, fname);
break;
}
}
if (bp == NULL && (bp = bfind (bname, TRUE)) == NULL)
{
err_echo (MSG_cnt_cr);
return (FALSE);
}
if (--curbp -> b_nwnd == 0)
{
/* Undisplay. */
curbp -> b_type = BTFILE;
curbp -> b_dotp = curwp -> w_dotp;
curbp -> b_doto = curwp -> w_doto;
curbp -> b_unit_offset = curwp -> w_unit_offset;
curbp -> b_markp = curwp -> w_markp;
curbp -> b_marko = curwp -> w_marko;
}
curbp = bp; /* Switch to it. */
curwp -> w_bufp = bp;
curbp -> b_nwnd++;
return (readin (fname, start, end)); /* Read it in. */
}
/*
* Read the file "fname" into the current buffer.
* Make all of the text in the buffer go away, after checking
* for unsaved changes. This is called by the "read" command, the
* "visit" command, and the mainline (for "beav file"). If the
* BACKUP conditional is set, then this routine also does the read
* end of backup processing. The BFBAK flag, if set in a buffer,
* says that a backup should be taken. It is set when a file is
* read in, but not on a new file (you don't need to make a backup
* copy of nothing). Return a standard status. Print a summary
* (lines read, error message) out as well.
*/
char readin (fname, start, end)
char fname[];
A32 start, end;
{
register LINE * lp1;
register LINE * lp2;
register WINDOW * wp;
register BUFFER * bp;
register char s, m;
long byte_cnt;
LPOS req_chars;
char buf[NCOL], buf1[NCOL];
A32 temp;
m = TRUE;
byte_cnt = 0;
bp = curbp; /* Cheap. */
if ((s = bclear (bp)) != TRUE)/* Might be old. */
return (s);
#if BACKUP
bp -> b_flag &= ~(BFCHG | BFBAK);/* No change, backup. */
#else
bp -> b_flag &= ~BFCHG; /* No change. */
#endif
if ((start == 0L) && (end == MAXPOS))
strcpy (bp -> b_fname, fname);
else
strcpy (bp -> b_fname, MSG_null);
bp -> b_file_size = 0;
bp -> b_type = BTFILE;
if ((s = ffropen (fname)) == FIOERR || s == FIOFNF)/* jam */
goto out;
bp -> b_file_size = file_len (); /* get the file lenth */
sprintf (buf, MSG_reading, fname);/* jam */
writ_echo (buf);
temp = ffseek (start);
if (temp != start)
{
sprintf (buf1, ERR_f_size, R_POS_FMT(curwp));
sprintf (buf, buf1, temp);
writ_echo (buf);
return (FALSE);
}
/* only read the requested number of characters */
if ((end - start) > NLINE)
req_chars = NLINE;
else
req_chars = (int)(end - start);
if ((lp1 = lalloc(req_chars)) == NULL)
{
bp -> b_flag |= BFVIEW; /* if no memory set to read only mode */
m = FALSE; /* flag memory allocation error */
}
else
{
while ((s = ffgetline (lp1->l_text, lp1->l_size, &lp1->l_used)) == FIOSUC)
{
/* this code breaks rules for knowing how lines * are stored and linked
together, oh well */
lp2 = lback (curbp -> b_linep);
lp2 -> l_fp = lp1;
lp1 -> l_fp = curbp -> b_linep;
lp1 -> l_bp = lp2;
curbp -> b_linep -> l_bp = lp1;
lp1 -> l_file_offset = byte_cnt; /* file offset from begining */
byte_cnt += (long) lp1 -> l_used; /* number of bytes read in */
start += (long) lp1 -> l_used;
if (end <= start)
break;
/* stop reading after the requested number of characters */
if (end < start + req_chars)
{
req_chars = end - start;
}
if ((lp1 = lalloc(req_chars)) == NULL)
{
bp -> b_flag |= BFVIEW; /* if no memory set to read only mode */
m = FALSE; /* flag memory allocation error */
break;
}
if ((byte_cnt & 0x7fff) == 0)
{
sprintf (buf1, MSG_read_lx, R_POS_FMT(curwp));
sprintf (buf, buf1, (ulong)byte_cnt);
writ_echo (buf);
/* check if we should quit */
if (ttkeyready ())
{
wind_on_dot_all();
if (ttgetc () == CTL_G) /* was it an abort key? */
{
s = FIOERR;
break;
}
}
}
}
}
ffclose (); /* Ignore errors. */
if (s == FIOEOF && kbdmop == NULL)
{
/* Don't zap an error. */
sprintf (buf1, MSG_read_lx, R_POS_FMT(curwp));
sprintf (buf, buf1, byte_cnt);
writ_echo (buf);
}
if (m == FALSE && kbdmop == NULL)
{
/* Don't zap an error. */
sprintf (buf, MSG_no_mem_rd);
err_echo (buf);
}
#if BACKUP
curbp -> b_flag |= BFBAK; /* Need a backup. */
#endif
out:
for (wp = wheadp; wp != NULL; wp = wp -> w_wndp)
{
if (wp -> w_bufp == curbp)
{
wp -> w_linep = lforw (curbp -> b_linep);
wp -> w_dotp = lforw (curbp -> b_linep);
wp -> w_doto = 0;
wp -> w_unit_offset = 0;
wp -> w_markp = NULL;
wp -> w_marko = 0;
wp -> w_flag |= WFMODE | WFHARD;
}
}
/* so tell yank-buffer about it */
if ((blistp -> b_nwnd != 0) && /* update buffer display */
(blistp -> b_type == BTLIST))
listbuffers ();
if (s == FIOERR || s == FIOFNF)/* False if error. */
return (FALSE);
return (TRUE);
}
/*
* Take a file name, and from it
* fabricate a buffer name. This routine knows
* about the syntax of file names on the target system.
* BDC1 left scan delimiter.
* BDC2 optional second left scan delimiter.
* BDC3 optional right scan delimiter.
*/
void makename (bname, fname)
char bname[];
char fname[];
{
register char *cp1;
register char *cp2;
cp1 = &fname[0];
while (*cp1 != 0)
++cp1;
#ifdef BDC2
while (cp1 != &fname[0] && cp1[-1] != BDC1 && cp1[-1] != BDC2)
--cp1;
#else
while (cp1 != &fname[0] && cp1[-1] != BDC1)
--cp1;
#endif
cp2 = &bname[0];
#ifdef BDC3
while (cp2 != &bname[NBUFN - 1] && *cp1 != 0 && *cp1 != BDC3)
*cp2++ = *cp1++;
#else
while (cp2 != &bname[NBUFN - 1] && *cp1 != 0)
*cp2++ = *cp1++;
#endif
*cp2 = 0;
}
/*
* Ask for a file name, and write the
* contents of the current buffer to that file.
* Update the remembered file name and clear the
* buffer changed flag. This handling of file names
* is different from the earlier versions, and
* is more compatable with Gosling EMACS than
* with ITS EMACS.
*/
char filewrite ()
{
register WINDOW * wp;
register char s;
char fname[NFILEN];
A32 start, end;
if ((s = ereply (MSG_wr_file, fname, NFILEN, NULL)) != TRUE)
return (s);
if (!parse_f_name (fname, &start, &end))
return (FALSE);
adjustcase (fname);
if ((s = writeout (fname, start, end, S_IREAD | S_IWRITE)) == TRUE)
{
strcpy (curbp -> b_fname, fname);
curbp -> b_flag &= ~BFCHG;
wp = wheadp; /* Update mode lines. */
while (wp != NULL)
{
if (wp -> w_bufp == curbp)
wp -> w_flag |= WFMODE;
wp = wp -> w_wndp;
}
}
#if BACKUP
curbp -> b_flag &= ~BFBAK; /* No backup. */
#endif
return (s);
}
/*
* Save the contents of the current buffer back into
* its associated file. Do nothing if there have been no changes
* (is this a bug, or a feature). Error if there is no remembered
* file name. If this is the first write since the read or visit,
* then a backup copy of the file is made.
*/
char filesave ()
{
register WINDOW * wp;
register char s;
struct stat st;
if ((curbp -> b_flag & BFCHG) == 0)/* Return, no changes. */
return (TRUE);
if (curbp -> b_fname[0] == 0)/* Must have a name. */
{
if (!(curbp -> b_type == BTSAVE))/* yanked buffer */
{
writ_echo (MSG_no_fn);
}
return (FALSE);
}
st.st_mode = S_IREAD | S_IWRITE; /* set default */
#if BACKUP
if ((curbp -> b_flag & BFBAK) != 0)
{
/* get the mode of the file */
stat (curbp -> b_fname, &st);
s = fbackupfile (curbp -> b_fname);
if (s == ABORT) /* Hard error. */
return (s);
if (s == FALSE /* Softer error. */
&& (s = eyesno (MSG_bk_err)) != TRUE)
return (s);
}
#endif
if ((s = writeout (curbp -> b_fname, 0L, MAXPOS, st.st_mode)) == TRUE)
{
curbp -> b_flag &= ~BFCHG;/* No change. */
curbp -> b_flag &= ~BFBAD;/* if it was trashed, forget it now */
wp = wheadp; /* Update mode lines. */
while (wp != NULL)
{
if (wp -> w_bufp == curbp)
wp -> w_flag |= WFMODE;
wp = wp -> w_wndp;
}
}
#if BACKUP
curbp -> b_flag &= ~BFBAK; /* No backup. */
#endif
return (s);
}
/*
* This function performs the details of file
* writing. Uses the file management routines in the
* "fileio.c" package. The number of lines written is
* displayed. Sadly, it looks inside a LINE; provide
* a macro for this. Most of the grief is error
* checking of some sort.
* The file permissions are set as requested.
*/
bool writeout (fn, start, end, mode)
char *fn;
A32 start, end;
ushort mode;
{
register int s, num_chars;
register LINE * lp;
register long nbytes;
char buf[NCOL], buf1[NCOL];
A32 temp;
if ((s = ffwopen (fn, mode)) != FIOSUC)/* Open writes message. */
return (FALSE);
temp = ffseek (start);
if (temp != start)
{
sprintf (buf1, ERR_f_size, R_POS_FMT(curwp));
sprintf (buf, buf1, temp);
writ_echo (buf);
return (FALSE);
}
sprintf (buf, MSG_writing, fn);/* jam */
writ_echo (buf);
/* insure that the help screen reflects the latest bindings */
if (curbp == blistp)
wallchart (0, 0, 0);
lp = lforw (curbp -> b_linep);/* First line. */
nbytes = 0; /* Number of bytes. */
temp = end - start; /* number of bytes to write */
while (lp != curbp -> b_linep)
{
if (curbp == blistp)
{
/* special list buffer */
num_chars = HENDCOL; /* limit line length */
lp -> l_text[num_chars - 1] = '\n';
}
else
{
/* standard buffer */
if (nbytes + (long)llength (lp) > temp)
num_chars = (int)(temp - nbytes);
else
num_chars = llength (lp);
}
if ((s = ffputline (&lp -> l_text[0], num_chars)) != FIOSUC)
break;
nbytes += num_chars;
if (temp <= nbytes)
break;
lp = lforw (lp);
if ((nbytes & 0x7fff) == 0)
{
sprintf (buf1, MSG_wrot_n, R_POS_FMT(curwp));
sprintf (buf, buf1, (ulong)nbytes);
writ_echo (buf);
/* check if we should quit */
if (ttkeyready ())
{
wind_on_dot_all();
if (ttgetc () == CTL_G) /* was it an abort key? */
{
s = FIOERR;
break;
}
}
}
}
if (s == FIOSUC)
{
/* No write error. */
s = ffclose ();
if (s == FIOSUC && kbdmop == NULL)
{
sprintf (buf1, MSG_wrot_n, R_POS_FMT(curwp));
sprintf (buf, buf1, (long) nbytes);
writ_echo (buf);
}
}
else /* Ignore close error */
ffclose (); /* if a write error. */
curbp -> b_file_size = nbytes; /* update file size */
if ((blistp -> b_nwnd != 0) && /* update buffer display */
(blistp -> b_type == BTLIST))
listbuffers ();
if (s != FIOSUC) /* Some sort of error. */
return (FALSE);
return (TRUE);
}
/*
* The command allows the user
* to modify the file name associated with
* the current buffer. It is like the "f" command
* in UNIX "ed". The operation is simple; just zap
* the name in the BUFFER structure, and mark the windows
* as needing an update. You can type a blank line at the
* prompt if you wish.
*/
char filename ()
{
register WINDOW * wp;
register char s;
char fname[NFILEN];
A32 start, end;
if ((s = ereply (MSG_fil_nam, fname, NFILEN, NULL)) == ABORT)
return (s);
if (!parse_f_name (fname, &start, &end))
return (FALSE);
adjustcase (fname);
curbp -> b_flag |= BFCHG; /* jam - on name change, set modify */
BUF_START(curwp) = start;
l_fix_up (curbp -> b_linep -> l_fp); /* adjust file offsets from first line */
strcpy (curbp -> b_fname, fname);/* Fix name. */
wp = wheadp; /* Update mode lines. */
while (wp != NULL)
{
if (wp -> w_bufp == curbp)
wp -> w_flag |= WFMODE;
wp = wp -> w_wndp;
}
#if BACKUP
curbp -> b_flag &= ~BFBAK; /* No backup. */
#endif
return (TRUE);
}
/*
* Get the length parameters that were entered with the file name.
* There can be the file name only.
* There can be a file name and a starting position.
* There can be a name a starting position and an ending position.
* There can be a name a starting position and a length.
*
* input:
* fn pointer to file name string to parse.
*
* output:
* fn pointer to null terminated file name.
* start pointer to the starting point in file (default = 0)
* end pointer to the end point in file (default = -1)
* return FALSE if file name or addresses are bad.
*/
bool parse_f_name (fn, start, end)
char *fn;
A32 *start, *end;
{
char buf[NFILEN], buf1[NCOL], fmt[NCOL];
int i_cnt;
/* build up format string according to the current screen format */
sprintf (fmt, "%s %s %s", "%s", R_POS_FMT(curwp), R_POS_FMT(curwp));
*start = 0L;
*end = MAXPOS;
sscanf (fn, fmt, buf, start, end);
if (*end != MAXPOS)
{
for (i_cnt = strlen (fn) - 1; i_cnt >= 0; i_cnt--)
{
if (fn[i_cnt] == '+')
{
*end += *start;
break;
}
}
}
/* start should preceed end */
if (*start > *end)
{
sprintf (buf1, ERR_parse_fn, R_POS_FMT(curwp), R_POS_FMT(curwp));
sprintf (buf, buf1, *start, *end);
writ_echo (buf);
return (FALSE);
}
/* error if addresses are negative */
if ((*start < 0) || (*end < 0))
{
writ_echo (ERR_addr_neg);
return (FALSE);
}
/* deposit null terminated file name */
strcpy (fn, buf);
return (TRUE);
}